﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Snowdreamist.ComponentModel;
using Snowdreamist.Threading;

namespace Snowdreamist.Web.Page
{
    public abstract class PageBase : NotifyPropertyBase, IPage
    {
        public PageBase(PageParserBase parser, Uri address)
        {
            if (parser == null)
                throw new ArgumentNullException("parser");

            if (address != null)
            {
                this.Address = address;
                this.Identity = address.ToString();
            }

            this.PageParserBase = parser;
            this._refreshTimer = new Timer(new TimerCallback(this.TimerCallback), null, Timeout.Infinite, 0);
        }

        #region Address

        private Uri _Address;

        /// <summary>
        /// Address
        /// </summary>
        public Uri Address
        {
            get { return this._Address; }
            set
            {
                if (this._Address != value)
                {
                    this._Address = value;
                    this.OnPropertyChanged("Address");
                }
            }
        }

        #endregion Address

        #region Identity

        private string _Identity;

        /// <summary>
        /// Identity
        /// </summary>
        public string Identity
        {
            get { return this._Identity; }
            set
            {
                if (this._Identity != value)
                {
                    this._Identity = value;
                    this.OnPropertyChanged("Identity");
                }
            }
        }

        #endregion Identity

        #region IsAutoRefresh

        private bool _IsAutoRefresh;

        /// <summary>
        /// IsAutoRefresh
        /// </summary>
        public bool IsAutoRefresh
        {
            get { return this._IsAutoRefresh; }
            set
            {
                if (this._IsAutoRefresh != value)
                {
                    this._IsAutoRefresh = value;
                    this.OnAutoRefreshChanged(value);
                    this.OnPropertyChanged("IsAutoRefresh");
                }
            }
        }

        #endregion IsAutoRefresh

        #region RefreshInterval

        private TimeSpan _RefreshInterval;

        /// <summary>
        /// RefreshInterval
        /// </summary>
        public TimeSpan RefreshInterval
        {
            get { return this._RefreshInterval; }
            set
            {
                if (this._RefreshInterval != value)
                {
                    var old = this._RefreshInterval;
                    this._RefreshInterval = value;
                    this.OnRefreshIntervalChanged(old, value);
                    this.OnPropertyChanged("RefreshInterval");
                }
            }
        }

        #endregion RefreshInterval

        public DateTime LastRefreshTime { get; protected set; }

        public IPageParser PageParser
        {
            get
            {
                return this.PageParserBase;
            }
        }

        public void Refresh()
        {
            if (Monitor.TryEnter(this))
            {
                try
                {
                    this.Content = this.RefreshCore();
                    this.LastRefreshTime = DateTime.Now;
                }
                catch (Exception error)
                {
                    this.LastRefreshTime = DateTime.Now;
                    this.OnRefreshed(error);
                }
                finally
                {
                    Monitor.Exit(this);
                }
            }
            else
            {
                // another refresh action is performing, return
                // do nothing
            }
        }

        public void RefreshAsync()
        {
            BackgroundJob.Run(new Action(() => this.Refresh()), "Page Parsing Thread for " + this.Identity);
        }

        public object Content { get; protected set; }

        public event EventHandler<RefreshedEventArgs> Refreshed;

        ~PageBase()
        {
            this.Dispose();
        }

        public void Dispose()
        {
            if (Interlocked.CompareExchange(ref this._isDisposed, 1, 0) == 0)
            {
                this._refreshTimer.Dispose();
                this.PageParserBase.DetachPage(this);
            }
        }

        #region protected

        protected PageParserBase PageParserBase { get; private set; }

        protected virtual void OnAutoRefreshChanged(bool isAutoRefresh)
        {
            if (isAutoRefresh)
            {
                // enable timer
                this._refreshTimer.Change(TimeSpan.Zero, this.RefreshInterval);
            }
            else
            {
                // disable timer
                this._refreshTimer.Change(Timeout.Infinite, 0);
            }
        }

        protected virtual void OnRefreshIntervalChanged(TimeSpan oldInterval, TimeSpan newInterval)
        {
            if (this.IsAutoRefresh)
            {
                this._refreshTimer.Change(newInterval, newInterval);
            }
        }

        protected virtual void OnRefreshed(Exception error)
        {
            if (this.Refreshed != null)
                this.Refreshed(this, new RefreshedEventArgs(error));
        }

        protected abstract object RefreshCore();

        #endregion protected

        #region private

        private int _isDisposed = 0;

        /// <summary>
        /// Refresh timer
        /// </summary>
        private Timer _refreshTimer;

        private void TimerCallback(object state)
        {
            this.RefreshAsync();
        }

        #endregion private
    }
}